home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Linux Cubed Series 7: Sunsite
/
Linux Cubed Series 7 - Sunsite Vol 1.iso
/
system
/
admin
/
pwdutils.00
/
pwdutils
/
pwdutils-1.00
/
passwd.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-05-16
|
17KB
|
726 lines
/*
** Copyright 1996 Thorsten Kukuk <kukuk@uni-paderborn.de>
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <pwd.h>
#include <stdio.h>
#include <ctype.h>
#include <unistd.h>
#include <string.h>
#include <getopt.h>
#include <malloc.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "pwdutils.h"
#include "version.h"
#define USER_NONE 0
#define USER_LOCAL 1
#define USER_NIS 2
#define USER_BOTH 3
#define MAX_LENGTH 1024
extern int __yp_check(char **);
extern struct passwd * __nis_getpwnam(const char *, void *);
static int whereis_user(const char *);
static int local_writeback(struct passwd *, char *);
static int check_gecos (char *, char *);
static void query_gecos_info (struct passwd *, struct npwd *);
char *progname;
static struct option chsh_options[] = {
{ "local-user", no_argument, 0, 'l' },
{ "nis-user", no_argument, 0, 'y' },
{ "shell", required_argument, 0, 's' },
{ "list-shells", no_argument, 0, '\255' },
{ "help", no_argument, 0, 'u' },
{ "usage", no_argument, 0, 'u' },
{ "version", no_argument, 0, 'v' },
{ NULL, no_argument, 0, '0' },
};
static char *chsh_str = "lys:uv";
static struct option chfn_options[] = {
{ "local-user", no_argument, 0, 'l' },
{ "nis-user", no_argument, 0, 'y' },
{ "full-name", required_argument, 0, 'f' },
{ "office", required_argument, 0, 'o' },
{ "office-phone", required_argument, 0, 'p' },
{ "home-phone", required_argument, 0, 'h' },
{ "help", no_argument, 0, 'u' },
{ "usage", no_argument, 0, 'u' },
{ "version", no_argument, 0, 'v' },
{ NULL, no_argument, 0, '0' },
};
static char *chfn_str = "lyf:o:p:h:uv";
static struct option passwd_options[] = {
{ "local-user", no_argument, 0, 'l' },
{ "nis-user", no_argument, 0, 'y' },
{ "shell", no_argument, 0, 's' },
{ "list-shells", no_argument, 0, '\255' },
{ "full-name", no_argument, 0, 'f' },
{ "help", no_argument, 0, 'u' },
{ "usage", no_argument, 0, 'u' },
{ "version", no_argument, 0, 'v' },
{ NULL, no_argument, 0, '0' },
};
static char *passwd_str = "lysfuv";
static void Usage(const char* progname)
{
if(strstr(progname,"passwd"))
{
printf("Usage: passwd [-l|-y] [-s|-f] [--list-shells] [-u] [-v] [user]\n");
exit(1);
}
if(strstr(progname,"chsh"))
{
printf("Usage: chsh [-l|-y] [-s shell] [--list-shells] [-u] [-v] [user]\n");
exit(1);
}
if(strstr(progname,"chfn"))
{
printf("Usage: chfn [-l|-y] [-f full-name] [-o office] [-p office-phone] [-h home-phone] [-v] [user]\n");
exit(1);
}
fprintf(stderr, "%s: What should I do? Call me passwd, chsh or chfn!\n",
progname);
exit(1);
}
int main(int argc, char *argv[])
{
struct passwd *pwd = NULL;
struct option *long_options;
struct npwd newf;
uid_t gotuid = getuid();
char *user, *opt_str;
char *master = NULL;
char *oldpassword = NULL;
int c, index;
int use_yp = 0;
int use_local = 0;
int query_passwd = 1;
int query_shell = 0;
int query_gecos = 0;
int result = 0;
memset (&newf, 0, sizeof (newf));
progname = argv[0];
if (strstr(argv[0],"yppasswd"))
{
use_yp = 1;
long_options = passwd_options;
opt_str = passwd_str;
}
else
if(strstr(argv[0],"ypchsh"))
{
use_yp = 1;
long_options = chsh_options;
opt_str = chsh_str;
query_passwd = 0;
query_shell = 1;
}
else
if(strstr(argv[0],"chsh"))
{
long_options = chsh_options;
opt_str = chsh_str;
query_passwd = 0;
query_shell = 1;
}
else
if(strstr(argv[0],"ypchfn"))
{
use_yp = 1;
long_options = chfn_options;
opt_str = chfn_str;
query_passwd = 0;
query_shell = 0;
query_gecos = 1;
}
else
if(strstr(argv[0],"chfn"))
{
long_options = chfn_options;
opt_str = chfn_str;
query_passwd = 0;
query_shell = 0;
query_gecos = 1;
}
else
{
long_options = passwd_options;
opt_str = passwd_str;
}
while((c = getopt_long(argc, argv, opt_str, long_options, &index))!= EOF)
{
switch(c)
{
case '\255':
print_shell_list(NULL);
exit(0);
break;
case 'l':
if(use_yp)
{
fprintf(stderr,"You could only change a NIS entry or ");
fprintf(stderr,"a local entry!\n");
exit(1);
}
use_local = 1;
break;
case 'y':
if(use_local)
{
fprintf(stderr,"You could only change a local entry or ");
fprintf(stderr,"a NIS entry!\n");
exit(1);
}
use_yp = 1;
break;
case 's':
if(query_gecos)
{
fprintf(stderr,"You could not specify -s and -f at the same time.\n");
Usage(argv[0]);
}
query_passwd = 0;
query_shell = 1;
if (optarg)
{
newf.shell = optarg;
/* root can set any shell he wish */
if(gotuid)
if(!check_shell(optarg))
return 1;
}
break;
case 'f':
if(query_shell)
{
fprintf(stderr,"You could not specify -s and -f at the same time.\n");
Usage(argv[0]);
}
query_passwd = 0;
query_gecos = 1;
if(optarg)
{
if(check_gecos("full name", optarg))
newf.full_name = optarg;
}
break;
case 'o':
if(check_gecos("office", optarg))
newf.office = optarg;
break;
case 'p':
if(check_gecos("office phone", optarg))
newf.office_phone = optarg;
break;
case 'h':
if(check_gecos("home phone", optarg))
newf.home_phone = optarg;
break;
case 'v':
printf("pwdutils %s\n", version);
exit (0);
break;
case 'u':
default:
Usage(argv[0]);
exit(0);
break;
}
}
argc-=optind;
argv+=optind;
umask (022);
if(argc > 1)
Usage(argv[0]);
else
if(argc == 1)
{
if(gotuid)
{
if(query_passwd)
fprintf(stderr,"Only root can change the password for others\n");
else
if(query_shell)
fprintf(stderr,"Only root can change the shell for others\n");
else
fprintf(stderr,"Only root can change the gecos fields for others\n");
exit(1);
}
user = argv[0];
}
else
{
if (!(user = getlogin()))
{
if (NULL==(pwd=getpwuid(getuid())))
{
perror("Cannot find login name");
exit(1);
}
else
user = pwd->pw_name;
}
}
if(!(pwd = getpwnam(user)))
{
fprintf(stderr,"Can't find username anywhere. Are you really a user?\n");
exit(1);
}
/* if somebody got into changing utmp... */
if(gotuid && gotuid != pwd->pw_uid)
{
puts("UID and username does not match, imposter!");
exit(1);
}
switch(whereis_user(user))
{
case USER_LOCAL:
if(use_yp)
{
fprintf(stderr,"%s is a local user, not a NIS.\n",user);
exit(1);
}
LOCAL_USER:
pwd = getpwnam(user);
break;
case USER_NIS:
if(use_local)
{
fprintf(stderr,"%s is a NIS user, not a local.\n",user);
exit(1);
}
else
use_yp = 1;
NIS_USER:
if(__yp_check(NULL) == 1)
{
static void *info_nis = NULL;
if (NULL == info_nis)
{
info_nis = __pwdalloc();
if (NULL == info_nis)
{
fprintf(stderr,"ERROR: __pwdalloc failed.\n");
exit(1);
}
pwd = __nis_getpwnam(user, info_nis);
if(pwd == NULL)
{
fprintf(stderr,"ERROR: Could not read NIS entry for %s\n",user);
exit(1);
}
}
}
else
{
fprintf(stderr,"ERROR: NIS not running anymore ?\n");
exit(1);
}
break;
case USER_BOTH:
if(use_yp)
goto NIS_USER;
else
{
use_local = 1;
goto LOCAL_USER;
}
break;
case USER_NONE:
default:
fprintf(stderr,"%s does not exist ?\n",user);
exit(1);
}
#ifdef DEBUG
printf("name.....: [%s]\n",pwd->pw_name);
printf("password.: [%s]\n",pwd->pw_passwd);
printf("user id..: [%d]\n",pwd->pw_uid);
printf("group id.: [%d]\n",pwd->pw_gid);
printf("gecos....: [%s]\n",pwd->pw_gecos);
printf("directory: [%s]\n",pwd->pw_dir);
printf("shell....: [%s]\n",pwd->pw_shell);
#endif
if (use_yp && (master = get_master_server()) == NULL)
{
exit(1);
}
if(query_passwd)
{
if(use_yp)
printf("Changing NIS password for %s on %s\n",pwd->pw_name,master);
else
printf("Changing password for %s\n",pwd->pw_name );
if(use_yp && pwd->pw_passwd && pwd->pw_passwd[0])
oldpassword = getoldpwd(pwd);
pwd->pw_passwd = getnewpwd(pwd);
if(use_yp)
{
result = yp_writeback(pwd,oldpassword,master);
if(result)
fprintf( stderr, "Error while changing NIS password.\n");
printf("NIS password has%s been changed on %s.\n",
result? " *NOT*" : "", master);
}
else
{
result = local_writeback(pwd,"Password");
printf("Password has%s been changed.\n",
result? " *NOT*" : "");
}
}
if(query_shell)
{
if(use_yp)
printf("Changing login shell for %s on %s\n",pwd->pw_name,master);
else
printf("Changing login shell for %s\n",pwd->pw_name);
if(use_yp && pwd->pw_passwd && pwd->pw_passwd[0])
oldpassword = getoldpwd(pwd);
if(!newf.shell)
newf.shell = prompt ("New shell", pwd->pw_shell);
if ((newf.shell == NULL) || (strcmp (pwd->pw_shell, newf.shell)==0))
{
printf ("Shell not changed.\n");
return 0;
}
if(gotuid)
if (!check_shell(newf.shell))
return 1;
pwd->pw_shell = newf.shell;
if(use_yp)
{
result = yp_writeback(pwd,oldpassword,master);
if(result)
fprintf( stderr, "Error while changing login shell.\n");
printf("Login shell has%s been changed on %s.\n",
result? " *NOT*" : "", master);
}
else
{
result = local_writeback(pwd,"Shell");
printf("Login shell has%s been changed.\n",
result? " *NOT*" : "");
}
}
if(query_gecos)
{
if(use_yp)
printf("Changing finger information for %s on %s\n",pwd->pw_name,master);
else
printf("Changing finger information for %s\n",pwd->pw_name);
if(use_yp && pwd->pw_passwd && pwd->pw_passwd[0])
oldpassword = getoldpwd(pwd);
parse_passwd(pwd, &newf);
if(!newf.full_name && !newf.office && !newf.office_phone &&
!newf.home_phone)
query_gecos_info(pwd, &newf);
if (! set_changed_finger_data(pwd, &newf))
{
printf ("Finger information not changed.\n");
return 0;
}
if(use_yp)
{
result = yp_writeback(pwd,oldpassword,master);
if(result)
fprintf( stderr, "Error while changing finger information.\n");
printf("Finger information has%s been changed on %s.\n",
result? " *NOT*" : "", master);
}
else
{
result = local_writeback(pwd,"Finger information");
printf("Finger information has%s been changed.\n",
result? " *NOT*" : "");
}
}
return result;
}
/*
** whereis_user - looks, if the user is local, NIS, both or none of them
*/
static int whereis_user(const char *user)
{
FILE *file;
int result;
struct passwd *pwd = NULL;
char line[MAX_LENGTH];
result = USER_NONE;
if((file = fopen("/etc/passwd","r"))==NULL)
{
fprintf(stderr,"ERROR: Can't open /etc/passwd\n");
exit(1);
}
while(fgets(line, MAX_LENGTH, file) != NULL)
{
int userlen = strlen(user);
if((strncmp(user,line,userlen) == 0) &&
(line[userlen] == ':'))
{
result+=USER_LOCAL;
break;
}
}
fclose(file);
if(__yp_check(NULL) == 1)
{
static void *info_nis = NULL;
if (NULL == info_nis)
{
info_nis = __pwdalloc();
if (NULL == info_nis)
return result;
}
pwd = __nis_getpwnam(user, info_nis);
if(pwd == NULL)
return result;
result+=USER_NIS;
}
return result;
}
/*
** local_writeback - returns 1 for a error, else 0
** At first, we locks the passwd file, then we copy it and
** change a passwd entry. "info" is, what we are changing
** (Password, Shell or Finger Information)
*/
static int local_writeback(struct passwd *pwd, char *info)
{
FILE *from, *to;
int done;
char *cptr, buf[8192];
pwd_init();
if(lckpwdf() != 0)
{
fprintf(stderr,"Can't lock /etc/passwd! Try again later.\n");
return 1;
}
if (!(from = fopen("/etc/passwd", "r")))
pwd_error("Couldn't open /etc/passwd",info);
if (!(to = fopen("/etc/passwd.tmp", "w")))
{
fclose(from);
pwd_error("Couldn't open /etc/passwd.tmp",info);
}
chmod("/etc/passwd.tmp",S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
for (done = 0; fgets(buf, sizeof(buf), from);)
{
if (!strchr(buf, '\n'))
{
fclose(from);
fclose(to);
pwd_error("/etc/passwd: line too long",info);
}
if (done)
{
fprintf(to, "%s", buf);
if (ferror(to))
{
fclose(to);
fclose(from);
pwd_error("unknown error by writing",info);
}
continue;
}
if (!(cptr = strchr(buf, ':')))
{
fclose(to);
fclose(from);
pwd_error("/etc/passwd: corrupted entry",info);
}
*cptr = '\0';
if (strcmp(buf, pwd->pw_name))
{
*cptr = ':';
fprintf(to, "%s", buf);
if (ferror(to))
{
fclose(to);
fclose(from);
pwd_error("unknown error by writing",info);
}
continue;
}
fprintf(to, "%s:%s:%d:%d:%s:%s:%s\n",
pwd->pw_name, pwd->pw_passwd, pwd->pw_uid, pwd->pw_gid,
pwd->pw_gecos, pwd->pw_dir, pwd->pw_shell);
done = 1;
if (ferror(to))
{
fclose(to);
fclose(from);
pwd_error("unknown error by writing",info);
}
}
if (!done)
{
fclose(to);
fclose(from);
fprintf(stderr,"user \"%s\" not found in /etc/passwd -- \
NIS maps and password file possibly out of sync", pwd->pw_name);
ulckpwdf();
return 1;
}
if (ferror(to))
{
fclose(to);
fclose(from);
pwd_error("unknown error by writing",info);
}
fclose(to);
fclose(from);
unlink("/etc/passwd");
rename("/etc/passwd.tmp","/etc/passwd");
ulckpwdf();
return 0;
}
/*
** query_gecos_info - prompt the user for the finger information
*/
static void query_gecos_info (struct passwd *pwd, struct npwd *newf)
{
printf("Changing finger information for %s.\n", pwd->pw_name);
newf->full_name = prompt("Name", newf->old_full_name);
while(!check_gecos("full name",newf->full_name))
{
printf("Try again\n");
free(newf->full_name);
newf->full_name = prompt("Name", newf->old_full_name);
}
newf->office = prompt("Office", newf->old_office);
while(!check_gecos("office", newf->office))
{
printf("Try again\n");
free(newf->office);
newf->office = prompt("Office",newf->old_office);
}
newf->office_phone = prompt ("Office Phone", newf->old_office_phone);
while(!check_gecos("office phone", newf->office_phone))
{
printf("Try again\n");
free(newf->office_phone);
newf->office_phone = prompt("Office Phone",newf->old_office_phone);
}
newf->home_phone = prompt ("Home Phone", newf->old_home_phone);
while(!check_gecos("home phone", newf->home_phone))
{
printf("Try again\n");
free(newf->home_phone);
newf->office = prompt("Home Phone",newf->home_phone);
}
}
/*
** check of the given gecos string is legal. If not,
** print "msg" followed by a description of the problem, and
** return 0. If it is legal, return 1
*/
static int check_gecos (char *msg, char *gecos)
{
unsigned int i;
char *c;
if((c=strpbrk(gecos,",:=\"\n")) != NULL)
{
if(msg)
printf("%s: ", msg);
printf("Invalid characters in gecos argument: '%c' is not allowed.\n",c[0]);
return 0;
}
for(i = 0; i < strlen(gecos); i++)
{
if(iscntrl(gecos[i]))
{
if(msg)
printf("%s: ", msg);
printf ("Control characters are not allowed.\n");
return 0;
}
}
return 1;
}